]> dgit.raspbian.org Git - pcre2.git/commitdiff
Backport of pcre2-10.48-Fix-compiler-integer-overflows.patch
authorNicholas Wilson <nicholas@nicholaswilson.me.uk>
Thu, 27 Aug 2026 15:52:16 +0000 (16:52 +0100)
committerMatthew Vernon <matthew@debian.org>
Tue, 1 Sep 2026 10:43:48 +0000 (11:43 +0100)
Cherry-pick of ec9c286d5c10cf1c388b58a442ccefded42254fd

Fix compiler integer overflows; see GHSA-fmgr-6ggq-9859 for details

(cherry picked from commit 983158a222ec27a93ce678778f9343f7dfa35845)

src/pcre2_compile.c
src/pcre2_compile_class.c

index 0ffac8939cb695fa81b58d8c8a8669e65939d167..78cc66a089e6b756b4200762914885e1cd58c4f5 100644 (file)
@@ -6069,7 +6069,8 @@ for (;; pptr++)
 
     if (meta < META_ASTERISK || meta > META_MINMAX_QUERY)
       {
-      if (OFLOW_MAX - *lengthptr < (PCRE2_SIZE)(code - orig_code))
+      if (*lengthptr > OFLOW_MAX ||
+          OFLOW_MAX - *lengthptr < (PCRE2_SIZE)(code - orig_code))
         {
         *errorcodeptr = ERR20;   /* Integer overflow */
         return 0;
@@ -8548,7 +8549,8 @@ for (;;)
     *reqcuflagsptr = reqcuflags;
     if (lengthptr != NULL)
       {
-      if (OFLOW_MAX - *lengthptr < length)
+      if (*lengthptr > MAX_PATTERN_SIZE ||
+          MAX_PATTERN_SIZE - *lengthptr < length)
         {
         *errorcodeptr = ERR20;
         return 0;
@@ -8571,6 +8573,19 @@ for (;;)
     {
     code = *codeptr + 1 + LINK_SIZE + skipunits;
     length += 1 + LINK_SIZE;
+
+    /* Move the accumulated length into *lengthptr, providing the next call to
+    compile_branch with as much space in &length and &code as the first did. */
+
+    if (*lengthptr > MAX_PATTERN_SIZE ||
+        MAX_PATTERN_SIZE - *lengthptr < length)
+      {
+      *errorcodeptr = ERR20;
+      cb->erroroffset = 0;
+      return 0;
+      }
+    *lengthptr += length;
+    length = 0;
     }
   else
     {
@@ -10626,7 +10641,8 @@ if (errorcode != 0) goto HAD_CB_ERROR;  /* Offset is in cb.erroroffset */
 #if defined SUPPORT_WIDE_CHARS
 PCRE2_ASSERT((cb.char_lists_size & 0x3) == 0);
 if (length > MAX_PATTERN_SIZE ||
-    MAX_PATTERN_SIZE - length < (cb.char_lists_size / sizeof(PCRE2_UCHAR)))
+    BYTES2CU(cb.char_lists_size) > MAX_PATTERN_SIZE ||
+    MAX_PATTERN_SIZE - length < BYTES2CU(cb.char_lists_size))
 #else
 if (length > MAX_PATTERN_SIZE)
 #endif
@@ -10650,11 +10666,36 @@ if (cb.char_lists_size != 0)
   /* Align to 32 bit first. This ensures the
   allocated area will also be 32 bit aligned. */
   re_blocksize = (PCRE2_SIZE)CLIST_ALIGN_TO(re_blocksize, sizeof(uint32_t));
+#else
+  /* Already 32 bit aligned. */
 #endif
+
+  /* We have bounded the length and BYTES2CU(char_lists_size) to
+  MAX_PATTERN_SIZE units, however (with 32-bit code units) char_lists_size
+  in bytes could still be extremely close to (or greater than) SIZE_MAX, so
+  we require another overflow check. */
+
+  if (cb.char_lists_size > PCRE2_SIZE_MAX - re_blocksize)
+    {
+    errorcode = ERR20;
+    cb.erroroffset = 0;
+    goto HAD_CB_ERROR;
+    }
+
   re_blocksize += cb.char_lists_size;
   }
 #endif
 
+if (length > BYTES2CU(PCRE2_SIZE_MAX - re_blocksize))
+  {
+  /* Given the current value of 2^30 for MAX_PATTERN_SIZE, this block is only
+  reachable when both PCRE2_CODE_UNIT_WIDTH >= 16 and sizeof(size_t) is
+  32 bits. */
+  errorcode = ERR20;
+  cb.erroroffset = 0;
+  goto HAD_CB_ERROR;
+  }
+
 re_blocksize += CU2BYTES(length);
 
 if (re_blocksize > ccontext->max_pattern_compiled_length)
@@ -10663,7 +10704,15 @@ if (re_blocksize > ccontext->max_pattern_compiled_length)
   goto HAD_CB_ERROR;
   }
 
+if (sizeof(pcre2_real_code) > PCRE2_SIZE_MAX - re_blocksize)
+  {
+  errorcode = ERR20;
+  cb.erroroffset = 0;
+  goto HAD_CB_ERROR;
+  }
+
 re_blocksize += sizeof(pcre2_real_code);
+
 re = (pcre2_real_code *)
   ccontext->memctl.malloc(re_blocksize, ccontext->memctl.memory_data);
 if (re == NULL)
index 0dd9e355d7451a2153ea930f290f264fa312ac6e..f3e7d1dd7475998d9dbad1431a6a407075a5c28f 100644 (file)
@@ -499,7 +499,7 @@ static const uint32_t char_list_starts[] = {
 
 static class_ranges *
 compile_optimize_class(uint32_t *start_ptr, uint32_t options,
-  uint32_t xoptions, compile_block *cb)
+  uint32_t xoptions, int *errorcodeptr, compile_block *cb)
 {
 class_ranges* cranges;
 uint32_t *ptr;
@@ -536,12 +536,23 @@ PCRE2_ASSERT((range_list_size & 0x1) == 0);
 
 total_size = range_list_size +
    ((range_list_size >= 2) ? CHAR_LIST_EXTRA_SIZE : 0);
+if (total_size > (PCRE2_SIZE_MAX - sizeof(class_ranges)) / sizeof(uint32_t))
+  {
+  *errorcodeptr = ERR20;
+  cb->erroroffset = 0;
+  return NULL;
+  }
 
 cranges = cb->cx->memctl.malloc(
   sizeof(class_ranges) + total_size * sizeof(uint32_t),
   cb->cx->memctl.memory_data);
 
-if (cranges == NULL) return NULL;
+if (cranges == NULL)
+  {
+  *errorcodeptr = ERR21;
+  cb->erroroffset = 0;
+  return NULL;
+  }
 
 cranges->next = NULL;
 cranges->range_list_size = (uint16_t)range_list_size;
@@ -1107,13 +1118,10 @@ if (utf)
   {
   if (lengthptr != NULL)
     {
-    cranges = compile_optimize_class(pptr, options, xoptions, cb);
+    cranges = compile_optimize_class(pptr, options, xoptions, errorcodeptr, cb);
 
     if (cranges == NULL)
-      {
-      *errorcodeptr = ERR21;
       return NULL;
-      }
 
     /* Caching the pre-processed character ranges. */
     if (cb->next_cranges != NULL)
@@ -1731,18 +1739,17 @@ if ((xclass_props & XCLASS_REQUIRED) != 0)
       *lengthptr += 1 + LINK_SIZE;
 #endif
 
-      cb->char_lists_size += char_lists_size;
-
-      char_lists_size /= sizeof(PCRE2_UCHAR);
+      PCRE2_ASSERT(BYTES2CU(cb->char_lists_size) <= MAX_PATTERN_SIZE);
 
-      /* Storage space for character lists is included
-      in the maximum pattern size. */
-      if (*lengthptr > MAX_PATTERN_SIZE ||
-          MAX_PATTERN_SIZE - *lengthptr < char_lists_size)
+      if (char_lists_size > PCRE2_SIZE_MAX - cb->char_lists_size ||
+          BYTES2CU(char_lists_size) > MAX_PATTERN_SIZE ||
+          BYTES2CU(cb->char_lists_size) > MAX_PATTERN_SIZE - BYTES2CU(char_lists_size))
         {
         *errorcodeptr = ERR20;   /* Pattern is too large */
         return NULL;
         }
+
+      cb->char_lists_size += char_lists_size;
       }
     else
       {
@@ -1765,6 +1772,8 @@ if ((xclass_props & XCLASS_REQUIRED) != 0)
       Each list is aligned to 32 bit with an optional unused
       16 bit value at the beginning of the character list. */
 
+      PCRE2_ASSERT(char_lists_size <= PCRE2_SIZE_MAX - cb->char_lists_size);
+
       cb->char_lists_size += char_lists_size;
       data = (uint8_t*)cb->start_code - cb->char_lists_size;